.\"/*
.\" * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
.\" * See https://llvm.org/LICENSE.txt for license information.
.\" * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
.\" *
.\" */
.NS 5 "Semantic Analyzer"
.de BS
.nr II \\n(ps
.nr ps 8
..
.de BE
.nr ps \\n(II
..
.sh 2 Overview
The Semantic Analyzer compiler module performs three major functions:
.BL
generates the first internal representation of the
executable statements of the user's subprogram (AST's).
.BL
enters symbols and their attributes into the symbol table
and related global data structures.
.BL
performs semantic error checking and issues appropriate
diagnostic messages.
.sp
.sh 2 "Data Structures"
.sh 3 "Global Data Structures"
.US "Symbol Table"
described in section 11.
.US "AST's"
internal representation of executable statements written to a temporary
file.  Refer to appendix IV
for a list of the AST opcodes and descriptions of their meanings.
.US "astb.df"
external temporary file containing information generated from the
processing of initializations.  See section 14.
.US "Data Initialization File"
external temporary file containing information generated by the Semantic
Analyzer and other phases to effect initializations of compiler-created
variables.
See section 14.
.US "Reference File"
external temporary file containing information on symbol usage
for the Cross Reference Listing.  See section 13.

.sp
.sh 3 "Semantic Stack"
The Semantic Stack is operated in parallel with the Parse Stack;
the same variable is used to point to the top of each (see section 4).
.lp
Each stack entry consists of 5 words (of type \*(cfINT\*(rf).  The contents
of each stack entry depend on the corresponding grammar symbol.
For example, for the symbol \*(gf<ident>\*(rf, the stack contains a
symbol table pointer to the identifier; for the symbol \*(gf<arg list>\*(rf
the stack contains pointers to the beginning and end of the
list, etc.
Each stack entry consists of an AST field.
.lp
For terminal symbols of the grammar, the first word of the
corresponding semantic stack entry is set to the token value returned
by the Scanner (see section 3).  For instance, for \*(gf<integer>\*(rf it 
is the 32-bit integer value of the constant.  The exceptions to this rule 
are constants requiring more than 32-bits of storage such as a 
complex constant.  In these cases the semantic stack entry contains a 
symbol table pointer to the constant.
.lp
For a non-terminal symbol, the sections of semantic code associated with
productions which generate the symbol are responsible for
ensuring that the proper values are put into the stack entry.
.lp 
Macros defined in \*(ffsemant.h\*(rf are used to access the words of 
the semantic stack.  These are of the form 
\*(cfSST_\*(gf<name>\*(cfP\*(rf and
\*(cfSST_\*(gf<name>\*(cfG\*(rf.
For example,
.CS

 SST_SYMG(s);
 SST_SYMP(s, sptr);
.CE
.lp
The most important type of stack entry is the one used
for \*(gf<expression>\*(rf and a number of other associated grammar
symbols such as \*(gf<primary>\*(rf, \*(gf<postfix exp>\*(rf, 
\*(gf<add exp>\*(rf, etc.
This entry itself has several formats, depending on the
value of the stack identifier.  The following macros are
used to reference the various fields described below:
.sp

.TS
tab (%) center;
l l.
FIELD%MACRO
_
.T&
l lfCW.
stack type%T{
SST_IDP, SST_IDG
T}
AST pointer%T{
SST_ASTP, SST_ASTG
T}
Constant value%T{
SST_CVALP, SST_CVALG
T}
Symbol pointer%T{
SST_SYMP, SST_SYMG
T}
.TE
.nr PI \n(psu
.nr ii 1.0i
.sp
.ip \*(cfS_EXPR\*(rf
AST's have been written for the associated expression.
.ba +1.0i
.nr ps 0
.sp \n(PIu
.ip word2
data type of the expression (pointer into dtype area, see section 11.4.1).
.ip word5
pointer to AST.
.nr ps \n(PIu
.ba -1.0i
.sp
.ip \*(cfS_LVALUE\*(rf
The expression is one which can be used as an lvalue,
and AST's have been written for it.
.ba +1.0i
.nr ps 0
.sp \n(PIu
.ip word2
dtype.
.ip word3
symbol of lvalue.
.ip word4
shape.
.ip word5
pointer to AST.
.nr ps \n(PIu
.ba -1.0i
.sp
.ip \*(cfS_LOGEXPR\*(rf
Logical expression.  An expression of the form
\*(cfe1 .and. e2\*(rf or \*(cfe1 .or. e2\*(rf, or 
the logical negation (\*(cf.not.\*(rf operator) of one of these.
See discussion of logical expression processing below.
.ba +1.0i
.nr ps 0
.sp \n(PIu
.ip word1
pointer to LAND or LOR AST.
.ip word2
dtype = \*(cfDT_INT\*(rf.
.ip word5
pointer to AST.
.nr ps \n(PIu
.ba -1.0i
.sp
.ip \*(cfS_CONST\*(rf
the associated expression is a constant.
.ba +1.0i
.nr ps 0
.sp \n(PIu
.ip word1
32-bit constant value if data type of
constant is an integer type,
otherwise a symbol table pointer to an
entry for the constant.
.ip word2
data type of the constant.
Note that although the Scanner only returns
constants of type \*(cfDT_INT\*(rf or \*(cfDT_FLOAT\*(rf, many other
data types are possible here because of the
constant folding of type cast operations.
.ip word5
pointer to AST.
.nr ps \n(PIu
.ba -1.0i
.ip \*(cfS_STAR\*(rf
created when
.cw *
is seen as a specifier for a dimension.
.ip \*(cfS_VAL\*(rf
created when the
.cw "%VAL"
built-in is seen;
word5 is the pointer to the AST of the operand.
.ip \*(cfS_IDENT\*(rf
identifier
.ba +1.0i
.nr ps 0
.sp \n(PIu
.ip word1
a symbol table pointer to an
entry for the identifier.
.ip word2
data type of the identifier.
.ip word5
pointer to A_ID AST.
.nr ps \n(PIu
.ba -1.0i
.ip \*(cfS_LABEL\*(rf
label
.ba +1.0i
.nr ps 0
.sp \n(PIu
.ip word1
a symbol table pointer to an
entry for the label.
.ip word5
pointer to the A_LABEL AST.
.nr ps \n(PIu
.ba -1.0i
.ip \*(cfS_STFUNC\*(rf
statement function definition
.ba +1.0i
.nr ps 0
.sp \n(PIu
.ip word1
a symbol table pointer to an
entry for the statement function which is being defined.
.ip word2
pointer to the list of the statement function's formal arguments.
.nr ps \n(PIu
.ba -1.0i

.ip \*(cfS_ACONST\*(rf
array constant
.ba +1.0i
.nr ps 0
.sp \n(PIu
.ip word1
a symbol table pointer to an
entry for the array temporary representing the constant.
.ip word2
its data type record.
.ip word3
the pointer to the array constructor list representing the
values of the array.
.nr ps \n(PIu
.ba -1.0i

.sp 
.sh 3 "Semantic Stack Lists"
Often a list of entities must be tied to a semantic stack entry.  This happens
for identifier lists to program entry points, array subscript lists,
subprogram call argument lists, and character substring lists.  The semantic
analyzer uses \*(tfitem lists\*(rf to retain semantic stack information until
enough information is gathered about the statement being parsed.  For example,
.CS

    foo(a, b, 1, 17, c)

.CE
could be an array reference or a function call.  Therefore, the semantic 
analyzer cannot generate ASTs while processing each of the arguments.  The
only alternative is to save any required information about the arguments in an
item list until it is determined what kind of reference is being made.
.lp
The following structure defines an item list.
.CS

    typedef struct xyyz {
	struct xyyz *next;
	int          ast;
	union {
	    int sptr;
	    struct sst *stkp;
	    INT conval;
	} t;
    } ITEM;

.CE
The first field of an item entry is used to point to the next item in the
list.  A value of \*(cfLIST_END\*(rf is used to mark the end of the list.
The second field is the AST pointer of the argument.
There are four types of item entries; symbol pointer,  semantic stack
pointer, and constant value.  They are each handled in a similar manner.  The
semantic stack item list entry is discussed here because it is more complex.
.lp
An argument list that could represent an array reference, character substring,
or function call is represented by an item list of semantic stack pointers.
An argument can be: 
.ip <expression>
a simple expression which denotes a function argument or a
single subscript, 
.ip "<ident> = <expression>"
an identifier keyword which is allowed in certain intrinsic or subprogram
calls, 
.ip <expression>:<expression>:<expression>
or a subscript triplet which denotes a vector slice.
.lp
.\"The SST_BEG and SST_END fields in a semantic stack entry point to the
.\"beginning and end of the argument list as follow:
.\".sp
.\".(b L
.\".br
.\".hl
.\".so ssa.pic
.\".sz 10
.\".ft R
.\".sp 2
.\".hl
.\".)b
.\".sp
\"
An argument that is a simple expression is represented by a semantic stack
entry of the normal type \*(cfS_IDENT\*(rf or \*(cfS_EXPR\*(rf.
.lp
An argument that is a keyword entry is represented by the corresponding
semantic stack id of S_KEYWORD.  The \*(cfSST_E3\*(rf field of the semantic
stack entry points to another semantic stack entry containing the expression.
.lp
An argument that is a subscript triplet is represented by a semantic stack id
of \*(cfS_TRIPLE\*(rf.  The \*(cfSST_E1\*(rf, \*(cfSST_E2\*(rf, and
\*(cfSST_E3\*(rf fields of that semantic stack entry point to other semantic
stack entries which represent the initial element, the ending element, and the
stride for the triplet notation.
.sp
.sh 3 "Structure Stack"
The structure stack is used to keep track of the current nesting of 
\*(cfSTRUCTURE\*(rf, \*(cfUNION\*(rf, and \*(cfMAP\*(rf 
statements.  The variables \*(cfsem.stsk_base\*(rf and
\*(cfsem.stsk_depth\*(rf are used to find the current stack top.  The
"Structure Processing" section describes how the structure stack is used by the
semantic analyzer.
.lp
The form of the structure stack is:
.CS

    typedef struct {  
	char   type;
        int    sptr;   
        int    dtype; 
	int    last;
        CONST *ict_beg; 
        CONST *ict_end;
    } STSK;
.CE
.BS
.ip \t\*(cftype\*(rf
the type of statement for which a stack entry represents ('s', 'u', or 'm'
for \*(cfSTRUCTURE\*(rf, \*(cfUNION\*(rf, or \*(cfMAP\*(rf, respectively).
.ip \t\*(cfsptr\*(rf
symbol table pointer to the first symbol in a linked list of symbols
representing the field name list of a \*(cfSTRUCTURE\*(rf statement.
For example, \*(cfSTRUCTURE /A/ B,C,D(10)\*(rf, the \*(cfsptr\*(rf would point
to \*(cfB\*(rf which is linked to \*(cfC\*(rf and \*(cfD\*(rf.
For \*(cfUNION\*(rf and \*(cfMAP\*(rf, this field is the symbol table
pointer to the compiler-created \*(cfST_MEMBER\*(rf symbol of
type  \*(cfTY_UNION\*(rf or \*(cfTY_STRUCT\*(rf, respectively.
.ip \t\*(cfdtype\*(rf
data type pointer to an entry of type \*(cfTY_STRUCT\*(rf (\*(cfTY_UNION\*(rf)
for the current structure.
.ip \t\*(cflast\*(rf
symbol table pointer to the last member which belongs to the
structure with respect to the scope.
All members which are at the same scoping level are linked together
via the \*(cfVARIANT\*(rf field in reverse order.
.ip \t\*(cfict_beg\*(rf
pointer to the beginning of the initializer constant tree for the
current structure.
.ip \t\*(cfict_end\*(rf
pointer to the end of the initializer constant tree for the
current structure.
.BE
.sh 3 "Initializer Constant Tree"
An Initializer Constant Tree is built (in dynamic storage) as the initializer 
for a static or external variable is processed (for automatic variables, AST's 
are generated as for an ordinary expression, then an assignment statement is 
simulated).
.lp
The tree consists of nodes linked by (absolute) pointers, and its structure 
parallels the tree defined by the nesting of braces ({}) in the C language form 
of the initializer and by \*(cfSTRUCTURE\*(rf's in the Fortran language form 
of the initializer.
.lp
Normally, when processing a data initialization statement, the initializer
constant tree is allocated, built, passed to \*(ffdinit.c\*(rf to generate
dinit records, and finally deallocated.  This all occurs during the processing
of a single Fortran statement.  This works for \*(cfDATA\*(rf statements and
type declaration statements but will not work for \*(cfSTRUCTURE\*(rf statements.
\*(cfSTRUCTURE\*(rf statements should not cause dinit records to be written.  
The dinit records should only be written for an instance of a structure declared 
with a \*(cfRECORD\*(rf statement.  This implies that the initializer constant 
tree cannot be deallocated during end of statement processing.  In fact, 
structure initializer constant trees must be allocated from memory that is not 
deallocated until end of program module processing.
.lp
The format of nodes is defined by the following C structure declaration:
.CS

    struct const {
        struct const *next;
        struct const *subc;
        INT           conval;
        INT           repeat;
        int           sptr;
        int           dtype;
    }
.CE
.lp
There are two types of nodes (distinguished by the value of subc):
.US "Set Node (subc != 0)"
represents a set of constants in a structure group.
.BS
.ip \t\*(cfnext\*(rf
pointer to next element of set (if any)
which is contained within the parent set.  \*(cfNULL\*(rf if this
set is at the top level, or is the last
element.
.ip \t\*(cfsubc\*(rf
pointer to the first element in the initializer constant tree of the
subordinate structure.
.ip \t\*(cfconval\*(rf
not used.
.ip \t\*(cfrepeat\*(rf
not used.
.ip \t\*(cfsptr\*(rf
Pointer to symbol table entry of variable, array, or structure member
to initialize.  If zero, the area we are currently initializing is continued
to be initialized.
.ip \t\*(cfdtype\*(rf
Data type record of the structure.
.BE
.lp
.US "Terminal Nodes (subc = 0)"
represent the occurrence of a constant (or constant expression)
in the initializer.
.BS
.ip \t\*(cfnext\*(rf
same as for Set Nodes.
.ip \t\*(cfsubc\*(rf
\*(cfNULL\*(rf.
.ip \t\*(cfconval\*(rf
32 bit constant value for integer types, else symbol table 
pointer to entry for constant.
.ip \t\*(cfrepeat\*(rf
The number of times to repeat the constant \*(cfin\*(rf conval.
.ip \t\*(cfsptr\*(rf
same as for Set Nodes.
.ip \t\*(cfdtype\*(rf
data type of the constant.
.BE

.sp
.sh 3 "Initializer Variable List"
An Initializer Variable List goes hand in hand with the Initializer Constant
Tree.  It contains the list of variables to be initialized by the constants
in the Constant Initializer Tree.  It is built in dynamic storage as the 
initializer for a static or external variable is processed.  The Initializer
Variable List is only used during \*(cfDATA\*(rf statement processing.
Therefore, its memory space can be released during end of statement
processing.
.lp
The format of the Initializer Variable List is:
.CS

    struct dinit_var {
        short id;    /* {Dostart, Doend, Varref} */
        union {
            struct {
                short indvar;
                short lowbd, upbd, step;
            } dostart;
            struct {
                struct dinit_var *dostart;
            } doend;
            struct {
		int id;
		int ptr;
		int dtype;
		int shape;
            } varref;
       } u;
       struct dinit_var *next;
 }
.CE
.lp
The \*(cfnext\*(rf field links together more than one variable list element.
A variable list element can be one of three types:  a simple variable
reference, an implied-do start, or an implied-do end.  
.nr ii 1.25i
.US "Simple Variable"
This is a variable, array, or array element reference.  Information from the
semantic stack is copied to this entry.
.BS
.ip \tid
This holds the value of the \*(cfSST_ID\*(rf field in the semantic stack.
.ip \tptr
This can either be a symbol table pointer or an AST pointer.  It will be an
AST pointer for an array element reference (i.e. it points to an SUBSCR
AST).
.ip \tdtype
This contains the data type of the variable from the semantic stack.
.ip \tshape;
This contains the shape of vector references from the semantic stack.
.BE
.US "Do-start"
This marks the beginning of an implied DO-loop.
.BS
.ip \tindvar\tlowbd\tupbd\tstep
This contains AST pointers to the index variable, the lower bound,
the upper bound, and the step increment for the DO-loop.
.ip \tstep
.BE
.US "Do-end"
This marks the end of an implied DO-loop.  It simply points back to the
associated Do-start entry.
.sp
.sh 3 "Loop Stack"
The Loop Stack is used to keep track of the
current nesting of do, while, and forall loops, and where and block
if statements.
It consists of fixed size records and is allocated a contiguous
area of dynamic storage.
The variable sem.loop_depth is used to find the current stack top.
.lp
Each record contains a field which is the beginning line number of the
control statement.
The remaining contents of a record depends on the type of loop it represents:
.nr ii 1.25i
.US "Do Loop"
.BS
.ip \tdo_label
symbol table pointer to the label of the last statement in the loop;
this field may be zero.
.ip \tdoinfo
pointer to the \f(CWDOINFO\fP record for the do/dowhile loop (see below).
.ip \tname
construct name.
This is just an index into the symbol names area; this field
is zero is the construct is unnamed.
.ip \texit_label
pointer to the symbol table entry for the label of any EXIT statement which
appeared in the DO body; 0 if an EXIT statement did not appear in the body.
.ip \tcycle_label
pointer to the symbol table entry for the label of any CYCLE statement which
appeared in the DO body; 0 if a CYCLE statement did not appear in the body.

.BE
.lp
.US "Do While Loop"
.BS
.ip \tdo_label
symbol table pointer to the label of the last statement in the loop;
this field may be zero.
.ip \tdoinfo
pointer to the \f(CWDOINFO\fP record for the do/dowhile loop.
.ip \tname
construct name.
.ip \texit_label
pointer to the symbol table entry for the label of any EXIT statement which
appeared in the DO body; if an EXIT statement did not appear in the body,
a label is created.
When the terminating statement of the dowhile statement is processed,
the do while loop is transformed into:
.CS
    top_label:
	if (.not. <dowhile expr>) goto exit_label;
	<body of dowhile>
	goto top_label;
    exit_label:
	<statement after dowhile>
.CE
.ip \tcycle_label
pointer to the symbol table entry for the label of any CYCLE statement which
appeared in the DO body; 0 if a CYCLE statement did not appear in the body.
.ip \top_label
pointer to the symbol table entry for the compiler-created label which
represents the top of the loop.

.BE
.lp
.US "Forall Loop"
.BS
.ip \tdo_label
0
.ip \tdoinfo
pointer to the \f(CWDOINFO\fP record for the do/dowhile loop (see below).
.ip \tname
0

.BE
.lp
.US "Block IF"
.BS
.ip \tdo_label
0
.ip \tdoinfo
0
.ip \tname
construct name

.BE
.lp
.US "Where"
.BS
.ip \tdo_label
0
.ip \tdoinfo
0
.ip \tname
construct name

.BE
.lp
For each DO and DOWHILE loop, a \f(CWDOINFO\fP record is created to record
additional information for the construct:
.US "DOINFO"
.BS
.ip \tindex_var
pointer to the symbol table entry for the DO index variable (DO loop only).
.ip \tinit_expr
ast of the initial expression (DO loop only).
.ip \tstep_expr
ast of the increment expression (DO loop only).
.ip \tlimit_expr
ast of the increment expression (DO loop only).
.ip \tcount
ast of the expression which computes the loop count (DO loop only).

.BE
.sp
.sh 3 "Array Constructor List"
When an array constructor is parsed, a list of array constructor items
is created.
An item, during parsing, is either an expression or an implied do
construct.
Each item is built in dynamic storage which is released during
end of statement processing.
.lp
The format of an array constructor item is:
.CS

    typedef struct _acl {
	int              id;
	struct _acl     *next;
	union {
	    struct sst  *stkp;
	    int          ast;
	    struct _acl *aclp;
	} t;
	union {
	    DOINFO      *doinfo;
	    INT          count;
	} u;
    } ACL;
.CE
.lp
The
.cw next
field links together the items.
The
.cw id
of an array constructor item while parsing is one of
.cw AC_EXPR
and
.cw AC_IDO .
.nr ii 1.25i
.US "AC_EXPR"
This represent an item which is an expression.
Information from the semantic stack is copied to this entry.
.BS
.ip \tstkp
This holds the value of the semantic stack for the expression.
.BE
.US "AC_IDO"
This marks the beginning of an implied DO-loop.
.BS
.ip \taclp
This is a pointer to an array constructor list under the control
of the implied do.
.ip \tdoinfo
This is a pointer to the
.cw DOINFO
record created for the implied do.
.BE
.sp
Other types of array constructor items are created when the
list is actually processed (after the parsing is complete).
The other fields in the structure are used during this processing.
.sp
.sh 2 Processing
.sh 3 Overview
.nr ii 5n
The Semantic Analyzer code can be divided into three parts:
.np
\fBInitialization\*(rf -  The \fIsemant_init\*(rf
routine which is called from the compiler 
\fIinit\*(rf routine to initialize the Semantic Analyzer data items and
allocate space for certain Semantic Analyzer data structures.
.np
\fBsemantic actions\*(rf - The body of the Semantic Analyzer logically
consists of a large switch statement with one case for each production
of the grammar (case labels are created by the parse table
generator utility - see section 4).
Because of the number of productions, the Semantic Analyzer is divided into
4 separate files:
.i semant
deals with declarations;
.i semant2
deals with expressions and simple statements;
.i semant3
deals with allocate statements, conditional statements, branching and call/function statements;
.i semantio
deals with I/O statements.
Each semantic action is responsible for performing the
processing associated with the particular production.
.np
\fButility routines\*(rf - routines called by the semantic actions to
do such things as
change expression types, perform constant folding, etc.  These
routines are found in the module \fIsemutil.c\*(rf.
The module \*(cfdinit.c\*(rf contains the routines to implement data
initialization statements and is discussed in the chapter.
.lp
The remainder of this section discusses a number of the
important semantic processing issues.
.nr ii 5n
.sh 3 "Declaration Processing"
The base data type of a symbol is kept globally and modified by
length specifiers and \f(CWKIND\fP specifiers.
For example, \*(cfINTEGER*2\*(rf will cause the 
global data type to be a \*(cfDT_SINT\*(rf.  When the symbols in the 
declaration list are analyzed the global data type is used by default.  
Of course the symbol can have its own length specifier, in which case 
its data type is chosen accordingly.  For example, 
\*(cfINTEGER*2 ZIGGY*1\*(rf will result in the symbol \*(cfZIGGY\*(rf 
having a data type \*(cfDT_BINT\*(rf.  Length and \f(CWKIND\fP
specifiers are only 
allowed in data type declaration statements.  The statements 
\*(cfDIMENSION\*(rf and \*(cfCOMMON\*(rf are not allowed to use
length specifiers. 
.lp
Data type declaration statements, \*(cfDIMENSION\*(rf statements, and 
\*(cfCOMMON\*(rf statements can modify a symbol to be an array.  For 
example, the symbol \*(cfZIGGY\*(rf could be defined as above and then 
specified as an array in a \*(cfDIMENSION\*(rf or \*(cfCOMMON\*(rf 
statement later.  The general rule is that the symbol's type can change 
from a simple variable to an array once.  If an attempt is made to change 
to an array again an error is flagged.
.lp
A declaration problem arises because of intrinsic functions.
When the declaration statement \*(cfREAL SIN\*(rf is encountered the 
compiler does not know whether the application programmer meant to simply 
reaffirm the declaration of the intrinsic function or that they are 
declaring a local variable called \*(cfSIN\*(rf.  It becomes simple if the 
symbol \*(cfSIN\*(rf were declared an array as in \*(cfREAL SIN(10)\*(rf, 
because this tells the compiler unequivocally that \*(cfSIN\*(rf is to be
used as a local array.  Likewise, if the compiler encounters the symbol 
\*(cfSIN\*(rf later in a \*(cfDIMENSION, COMMON\*(rf, or \*(cfEQUIVALENCE\*(rf 
statement it knows that the symbol \*(cfSIN\*(rf is to lose its intrinsic 
properties.  
If none of these events happens then the compiler must wait until the 
first reference to the symbol to determine its intended use.
.lp
If the following first reference was encountered then the
symbol \*(cfSIN\*(rf is assumed to be a local variable and the intrinsic 
\*(cfSIN\*(rf will not be available to the application programmer.
.CS

	sin = sqrt(100)
.CE
.lp
If the following statement were encountered as the first reference then the
symbol \*(cfSIN\*(rf is reaffirmed as the intrinsic \*(cfSIN\*(rf and the 
intrinsic is frozen, that is, it can only be used as an intrinsic in the 
current program section.
.CS

	x = sin(x)
.CE

.sp
.sh 3 "Interface Blocks"
A subprogram for which an interface is explicitly specified is entered
in the same scope (level 0) as the main subprogram and its variables.
Any variables declared, such as the dummy arguments, are entered into the
symbol table at a scope 1 greater than the current scope.
When the \f(CWEND\fP statement for the subprogram is seen, the scope
is
.i popped
(the symbols in scope are removed from the symbol table's hash table),
thus hiding the symbols declared in the scope from the rest of the
subprogram.
Since subprograms declared in an interface block
do not inherit any information from their
.i host ,
entities, such as the implicit rules and named (parameter) constants
are hidden from the semantic analysis of the interface block.
Hiding the implicit rules is performed by
.i pushing
the current rules onto a stack
and
.i references
to outer-scoped parameters are hidden by restricting the scope levels
which can be accessed if in an interface block.
.sp
.sh 3 "Structure Processing"
The top of the structure stack represents the
\*(cfSTRUCTURE\*(rf statement currently being parsed and the preceeding stack
entries represent uncompleted \*(cfSTRUCTURE\*(rf statements that were
interrupted by nested \*(cfSTRUCTURE\*(rf statements.
.lp
The goal of processing a \*(cfSTRUCTURE/END STRUCTURE\*(rf block of statements
is to create a data type for the structure being declared.  The data type
entry has a pointer to a linked list of structure members and a pointer
to the initializer constant tree for the members that are data initialized
(see "Initializer Constant Tree" section).  The following example will show
how the nesting of structures is handled by the structure stack.
.CS

    structure /a/ 
	integer b /2/
	structure /c/ d
	    integer e /3/
	end structure
    end structure
.CE
.sp
The data type for structure tag \*(cfa\*(rf will point to the list of members
\*(cfb\*(rf and \*(cfd\*(rf, and will point to an initializer constant tree
containing the constant \*(cf2\*(rf.  At the point where structure \*(cfc\*(rf
is encountered, the state for structure \*(cfa\*(rf must be saved on the
structure stack so that it is not confused with structure \*(cfc\*(rf.
Structure \*(cfc\*(rf has its own member list and initializer constant tree
built and initialized in a new data type of its own.  When the \*(cfEND
STRUCTURE\*(rf for structure \*(cfc\*(rf is encountered the structure stack is
popped and the processing for structure \*(cfa\*(rf is continued.
.sp
.sp
.sh 3 "Initializer Processing"
The Initializer Constant Tree and Initializer Variable List are built as
the Semantic Analyzer processes data initialization statements.
These data structures are passed to the routine \*(mfdinit\*(rf in the module
\*(cfdinit.c\*(rf which 
matches each variable with a constant and writes the necessary records 
to the Data Initialization File.  The Semantic Analyzer is responsible 
for handling the various special features of Fortran initializers, such as:
.BL
repeated constant fields
.BL
whole array initializations
.BL
partial array initializations
.BL 
three forms of initialization syntax; \*(cfDATA\*(rf statements, type declaration
statements, and \*(cfSTRUCTURE\*(rf statements
.lp
The three forms of data initialization statements are discussed in the
following sections.
.sp
.sh 4 "DATA Statements"
The following \*(cfDATA\*(rf statement will be used as an example.
.CS

        INTEGER a, b(5), c(2,4,3)
        DATA a, b, c(1,2,3), c(2,3,2) / 3*1, 5*4/
.CE
.lp
Data statement processing requires passing both an Initializer 
Constant Tree and a Initializer Variable List to the \*(cfdinit\*(rf
routine.  Processing requires a walk of both the Initializer Constant Tree and
the Initializer Variable List assigning constants to variables.
.lp
The \*(cfDATA\*(rf statement is the only initializing statement that allows
implied \*(cfDO\*(rf-loops and array element initialization.  
Record references are not allowed in \*(cfDATA\*(rf statements.
.lp
In the example the variables \*(cfa\*(rf and the first 2 elements of 
the array \*(cfb\*(rf will be initialized to the constant 1.  Three elements
of the array \*(cfb\*(rf and two elements in the array \*(cfc\*(rf 
will be initialized to the constant 4.  Here is the Initializer Constant 
Tree and the Initializer Variable List the \*(cfdinit\*(rf would process.
.ne 7
.CS

  IVL ---> a ---> b ---> c ---> c

  ICT ---> next ---> next
           Term      Term
           3*1       5*4
           0         0
.CE
.lp
The entries for \*(cfc\*(rf will contain AST pointers for array element
referencing.  These AST pointers will be traced back by \*(cfdinit\*(rf
to determine the array element being initialized.
.lp
The \*(cfDATA\*(rf statement is the only form of data initialization statement
that allows implied DO-loops.  The following example is used to describe the
processing of implied DO-loops.
.ne 13
.CS

        DATA ((a(i,j), i=1, 10), j = 21, 30) / 100*42.0 /

  IVL ---> dostartj ---> dostarti ---> a ---> doendi ---> doendj
           j             i 
           21            1
           30            10
           1             1

  ICT ---> next
           Term
           100*42.0
           0
.CE
.lp
The values in the \*(cfIVL\*(rf structures above are actually AST links.
When the array element reference to \*(cfa\*(rf is encountered, the AST links
are scanned and the array indexes \*(cfi\*(rf and \*(cfj\*(rf are evaluated.
The offset from the beginning of array \*(cfa\*(rf is computed so that the
dinit record can be generated.
.lp
When \*(cfdoendj\*(rf is encountered, the corresponding \*(cfdostarti\*(rf is
located.  Then the index variable \*(cfi\*(rf is incremented by the step
amount and a test is made to see if the upper bound has been exceeded.
If the inner implied DO-loop controlled by index variable \*(cfi\*(rf does not
exceed its upper bound then we reset the \*(cfIVL\*(rf pointer back to process
\*(cfa\*(rf again, this time with an updated index variable \*(cfi\*(rf.
Later when the index variable \*(cfi\*(rf does exceed its upper bound we do
not back up, we simply move forward to the \*(cfdoendj\*(rf entry.  Processing
for the outer implied DO-loop is exactly the same as for the inner DO-loop.
.sp
.sh 4 "Type Declaration Initializations"
Data initializations can occur within a type declaration statement.  The
following example will be used.
.CS

        INTEGER a(30) /5*2, 5*3, 10*4/, b/1/
.CE
.lp
In this example the array \*(cfa\*(rf will be initialized with 20 constants;
five locations with 2, five locations with 3, and ten locations with 4.
The variable \*(cfb\*(rf will be initialized with the constant 1.
Notice that the type declaration statement does two things.
It declares the number of elements in an array and it initializes that array
starting from its base address.
.lp
Record references are not allowed with this form of data initialization.
Implied \*(cfDO\*(rf-loop specifiers are not allowed with this 
type of declaration.  
.lp
In the example above, the \*cfdinit\*(rf routine will be called twice.
An Initializer Variable List is not used.  The variable information is
embedded within the Initializer Constant Tree.  Here is the Initializer 
Constant Tree for each call:
.CS

  ICT ---> next ---> next ---> next
           Term      Term      Term
           5*2       5*3       10*4
           a         0         0

  ICT ---> next
           Term
           1
           b
.CE
.lp
The first ICT will cause the \*(cfdinit\*(rf routine to begin with the base
address of \*(cfa\*(rf.  It will write dinit records to initialize the first
two elements of \*(cfa\*(rf with the constant 2, then since the next ICT
entry does not have a new symbol table pointer entry, the next five constant
3's will go into \*(cfa(3), a(4),\*(rf and \*(cfa(5)\*(rf.  The remaining ten
constant 4's are assigned locations similarly.  Notice that it is not a
problem that there are not enough contants to initialize the entire array.
However, too many constants would be a problem.
.sp
.sh 4 "STRUCTURE Data Initializations"
The following \*(cfSTRUCTURE\*(rf statement will be used as an example.
.CS

        structure /s0/
            integer a(40) /10*5, 10*10, 10*15/
            real b(10)
            integer c/6/
        end structure
        structure /s1/
            integer a, b(30)/30*42/
            structure /s2/ c
	        integer a /42/
            end structure
            real d, e(30)
            record /s0/ f
        end structure
        record /s1/ r1, r2(30)
.CE
.lp
Structure initializations differ from the other forms of data initializations.
The occurrance of data initialization within a structure statement does not
cause dinit records to be generated.  The dinit records would be generated
when an instance of the structure was declared via the \*(cfRECORD\*(rf
statement.  This implies that the Initializer Constant Tree for a structure
must not be deallocated during end of statement processing as it does with the
other forms of initialization statements.  It must be kept around until end of
program module processing.  The data type entry for a structure contains a
pointer to the structure's Initializer Constant Tree.
.lp
Structure initializations use the same form of Initializer Constant Tree as
does the Type Declaration Initialization statements.  The structure tag entry
and the structure in the symbol table will have a pointer the structure's 
data type entry.  From this the structure's Initializer Constant Tree can be
located.
.lp
Here are the Initializer Constant Trees for our example.
.CS

 ICT s0
 ---> next ---> next ---> next ---> next
      Term      Term      Term      Term
      10*5      10*10     10*15     6
      a         0         0         c

 ICT s1
 ---> next ---> next ---------> next
      Term      Subc (ICT s2)   Subc (ICT s0)
      30*42     ---             ---
      b         c               f

 ICT s2
 ---> next
      Term
      42
      a
.CE
.lp
Notice that the Initializer Constant Tree for structure \*(cfs1\*(rf 
contains references to the Initializer Constant Trees for other structures.
Also, the \*(cfsptr\*(rf field in an entry contains a symbol table pointer to
a member of a structure.  This is used to get the offset from the beginning of
a structure for a particular member.  For example, to obtain the offset from
the beginning of record \*(cfr1\*(rf for the member r1.c.a you would first
calculate the offset from the beginning of \*(cfr1\*(rf to its member
\*(cfc\*(rf, then add to that the offset from the beginning of 
\*(cfc\*(rf to its member \*(cfa\*(rf.
.lp
Implied \*(cfDO\*(rf-loops and partial array initialization is not allowed.

.sp
.sh 3 "Expressions"
When a reduction is made for an arithmetic, character, or logical
operation, such as
.CS

<addition> ::= <arith expr> <addop> <term> ,

.CE
the semantic action code typically performs the following steps:
.np
The data types of the operands are checked and AST's generated
to convert the data type of one or both of the operands if necessary.
Hollerith and non-decimal constants are handled by data type assumption
rather than data type conversion.  Both of the operands would be converted 
for the case where one operand is doubleprecision and the other operand 
is complex.  In this case both operands are converted to doublecomplex.
.np
Each operand is checked to see if one requires a scalar to vector promotion.
.np
If both operands are constant, the operation is constant folded.
Constant folding is also done in the Expander, but is required
here for array bounds, initializers, and switch labels.
.np
Otherwise the routine \*(mfmkexpr\*(rf
is called for each operand, to ensure that
AST's have been generated.
.np
The AST for the operation is added.
.np
The stack entry corresponding to the left hand side of the
reduction is set up with the AST pointer to the added AST,
and information on the data type of the expression.
.sp
.sh 3 "Logical Expressions"
A \*(tflogical expression\*(rf is one of the form 
\*(cfe1 .or. e2\*(rf, \*(cfe1 .and. e2\*(rf, or the negation
operator \*(cf.not. e1\*(rf.
.sh 3 "Array Constructors"
After an array constructor list created during parsing, the list
is analyzed by the function
.cw mk_constructor() .
The result of this function is a semantic stack entry
of type \f(CWS_IDENT\fP or \f(CWS_ACONST\fP.
In either case, an array temporary is created which represents the
value of the constructor.
In the former case, code is generated to define the values of the
temporary; in the latter case, enough information is saved so that
data initialization records are created when (if) the constructor
is actually referenced.
.lp
The first step in
.cw mk_constructor()
is to compute the size of the constructor.
A side-effect of this step is to determine if the temporary can
be data initialized.
Data initialization will occur only if the following criteria are met:
.np
implied do's are not present and all of the items are constants, or
.np
the context requires an array constant,
implied do's with constant bounds are present,
the expressions under the control of the implied do's will yield constants,
and all other items are constants.
.lp
.sp
.sh 3 "Intrinsic Processing"
Intrinsic functions are supplied by the processor and have a special meaning.
Generic names simplify the referencing of specific intrinsic functions.  
They allow the function argument to be of any type and provide a mapping 
to the specific intrinsic function based on the data type of the argument.  
.lp
Generic names cannot be used to pass an intrinsic function as an actual 
argument.  Specific intrinsic names can be passed as an argument only if 
they have been confirmed as intrinsics (see below).  If not confirmed, 
then they are treated as variables.
.lp
An intrinsic name is predefined by the compiler.  The name
can be confirmed as an intrinsic function or can have its intrinsic property
taken away.  If the compiler encounters one of the cases that confirms the 
intended use of a symbol as an intrinsic function, then that symbol is
\*(tffrozen\*(rf and can only be used to reference that intrinsic
function for the remainder of the program unit.  If the compiler encounters
one of the cases that removes the symbol's intrinsic property, then that
symbol is redefined and must be used in a manner according to the user's
overriding definition and cannot be used as an intrinsic function for the
remainder of the program unit.  
.lp
\*(tfCASE 1: CONTEXTS HAVING NO EFFECT ON INTRINSIC NAMES\*(rf
.np
A specific intrinsic name occuring in a type declaration alone, does not 
effect the intrinsic name.  If the name is later confirmed as an intrinsic
name then the type declaration has not effect.  If the name is later used in a
context that removes the intrinsic property of the name, then the name takes
on the data type specified in the type declaration encountered earlier.
.lp
\*(tfCASE 2: CONTEXTS CAUSING INTRINSIC CONFIRMATION\*(rf
.np
Use of a name in the \*(cfINTRINSIC\*(rf statement.
.np
Use of a name that agrees in context and number and type of arguments
with the predefined intrinsic confirms that name as an intrinsic.
.lp
\*(tfCASE 3: CONTEXTS CAUSING INTRINSIC PROPERTY REMOVAL\*(rf
.np
In general, use of an intrinsic function name in a non-executable 
statement other than the type specification statements removes the 
intrinsic property of that name.
.np
An intrinsic name declared as an array via a type specification statement
removes the intrinsic property of that name.
.np
The use of a symbol on the left side of an assignment statement removes
a symbol's intrinisic property if its intrinsic property is not already
confirmed.
.np
The use of a symbol without the correct number and type of arguments in
an expression removes the symbol's intrinsic property if its intrinsic
property is not already confirmed.
.lp
.ne 10
.TS
tab(%) expand;
c s s
lfCW lfCW lfCW.
_
\s+1EXAMPLES\s0

subroutine a%subroutine b%subroutine c
real exp%integer exp%integer exp
x = exp(x)%x = exp(x)%x = exp
end%end%end
_
.TE
In subroutine \*(cfa\*(rf and \*(cfb\*(rf, the type declaration statement 
has no effect on
the intrinsic property of symbol \*(cfexp\*(rf.  In subroutine \*(cfb\*(rf,
the symbol \*(cfexp\*(rf will be redefined as an integer variable.
.sp

